package security;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.SecretKeySpec;
import constans.SizeConstans;

/**
 * This class implements the abstract class CipherFile using the AES algorithm
 *
 */
public class CipherFileAES extends CipherFile {

	/**
     * The size of the key
     */
	public static final int keySize = 16;
	
    /**
     * Cipher object  for encryption and decryption
     */
	private Cipher cipher;

    /**
     *SecretKeySpec object specifies a secret key in a provider-independent fashion
     */
	private SecretKeySpec skeySpec;


    /**
     *
     * Class constructor specifying key
     *
     * @param keyBytes key
     * @throws java.security.InvalidKeyException If an exception for invalid Keys (invalid encoding, wrong length, uninitialized, etc)  error occurs
     * @throws java.security.GeneralSecurityException If an generic security exception error occurs
     */
    public CipherFileAES(byte [] keyBytes)
            throws InvalidKeyException, GeneralSecurityException{
		
		if(keyBytes.length!=keySize)
			throw new InvalidKeyException("Invalid key length:"+keyBytes.length+" bytes");
		
		cipher = Cipher.getInstance("AES");
		skeySpec = new SecretKeySpec(keyBytes, "AES");	
	}   

	

	protected void encode(File inFile, File outFile)
            throws IOException{

        InputStream inStream = null;
		OutputStream outStream = null;

		try {

            cipher.init(Cipher.ENCRYPT_MODE,skeySpec);
            
			inStream = new FileInputStream(inFile);
			outStream = new CipherOutputStream(new FileOutputStream(outFile),cipher);

			int numRead = 0;
			byte[] buffer = new byte[(int)SizeConstans.KByte];

			while ((numRead = inStream.read(buffer)) >= 0)
				outStream.write(buffer, 0, numRead);
			outStream.flush();

			inStream.close();
			inStream = null;

			outStream.close();
			outStream = null;
			
		}  catch (IOException e) {
			try {
				if(inStream!=null){
					inStream.close();
					inStream = null;
				}
			} catch (IOException e1) {}
			try {
				if(outStream!=null){
					outStream.close();
					outStream = null;
				}
			} catch (IOException e1) {}
			throw new IOException(e);
		} catch (InvalidKeyException e) {}
	}


	protected void decode(File inFile, File outFile)
            throws IOException{

        
		InputStream inStream = null;
		OutputStream outStream  = null;
		
		try {			

            cipher.init(Cipher.DECRYPT_MODE,skeySpec);
            
			inStream = new CipherInputStream(new FileInputStream(inFile), cipher);
			outStream = new FileOutputStream(outFile);

			int numRead = 0;
			byte[] buffer = new byte[(int)SizeConstans.KByte * 512];
            
			while ((numRead = inStream.read(buffer)) >= 0)
				outStream.write(buffer, 0, numRead);	
			outStream.flush();

			inStream.close();
			inStream = null;

			outStream.close();
			outStream = null;

		} catch (IOException e) {
			try {
				if(inStream!=null){
					inStream.close();
					inStream = null;
				}
			} catch (IOException e1) {}
			try {
				if(outStream!=null){
					outStream.close();
					outStream = null;
				}
			} catch (IOException e1) {}
			throw new IOException(e);
		} catch (InvalidKeyException e) {}
	}


}
